Developing Serverless Solutions on AWS - Live Session Guide
This module covers how Lambda processes events from queues (SQS) and streams (Kinesis, DynamoDB Streams) using event source mappings (polling-based invocation).
Unlike async invocations (EventBridge/SNS push to Lambda), queues and streams require Lambda to poll for records.
Queues provide a buffer between a producer and a single consumer. Messages are processed and deleted.
| Behavior | Detail |
|---|---|
| Polling | Lambda starts with 5 polling processes, scales up based on queue depth |
| Batching | 1-10,000 messages per batch (configurable). Max 10 for Standard, 10,000 for FIFO. |
| Visibility Timeout | Messages become invisible while being processed. Set to 6x your Lambda timeout. |
| Deletion | Lambda deletes messages from queue after successful processing of entire batch |
| Failure | Failed messages return to queue after visibility timeout. Use DLQ after N failures. |
| Concurrency | One Lambda instance per batch. Multiple batches = multiple concurrent instances. |
| Partial Batch | Report individual failures with ReportBatchItemFailures (only retry failed items) |
Resources:
OrderQueue:
Type: AWS::SQS::Queue
Properties:
VisibilityTimeout: 180 # 6x Lambda timeout (30s)
RedrivePolicy:
deadLetterTargetArn: !GetAtt OrderDLQ.Arn
maxReceiveCount: 3
OrderDLQ:
Type: AWS::SQS::Queue
ProcessOrderFn:
Type: AWS::Serverless::Function
Properties:
Handler: app.handler
Runtime: python3.12
Timeout: 30
Events:
SQSEvent:
Type: SQS
Properties:
Queue: !GetAtt OrderQueue.Arn
BatchSize: 10
FunctionResponseTypes:
- ReportBatchItemFailures
Streams buffer data arriving continuously and support multiple consumers. Data is retained (not deleted on read).
| Behavior | Detail |
|---|---|
| Shard-based | Lambda maintains one iterator per shard, processes sequentially within each shard |
| Batching | 1-10,000 records per batch. Configurable batch window (up to 5 min). |
| Ordering | Records within a shard are processed in order (partition key determines shard) |
| On failure | Default: block until batch succeeds or data expires. Configurable: skip, bisect, send to destination. |
| Concurrency | 1 concurrent invocation per shard (default). Parallelization factor: up to 10 per shard. |
| Pointer | Lambda tracks position in stream. On success, advances pointer. On failure, retries from same position. |
| Feature | Kinesis Data Streams | DynamoDB Streams |
|---|---|---|
| Polling rate | 1x per second per shard | 4x per second per shard |
| Shard count | You set manually (or auto-scale) | Automatic (driven by table capacity) |
| Scaling | Manual shard splitting/merging or auto-scaling | Shards scale with table - Lambda concurrency increases too |
| Retention | 24 hours - 365 days | 24 hours (fixed) |
| Use case | Real-time analytics, log aggregation, IoT | React to table changes (triggers) |
| Consumers | Multiple (enhanced fan-out available) | Up to 2 consumers per table |
# Event source mapping configuration for streams
EventSourceMapping:
Type: AWS::Lambda::EventSourceMapping
Properties:
EventSourceArn: !GetAtt MyStream.Arn
FunctionName: !Ref ProcessStreamFn
StartingPosition: LATEST
BatchSize: 100
MaximumBatchingWindowInSeconds: 5
ParallelizationFactor: 2 # 2 concurrent per shard
MaximumRetryAttempts: 3 # Don't block forever
BisectBatchOnFunctionError: true # Split batch to find bad record
MaximumRecordAgeInSeconds: 86400 # Skip records older than 1 day
DestinationConfig:
OnFailure:
Destination: !GetAtt FailedRecordsSQS.Arn # Send failures to DLQ
| Criteria | Queue (SQS) | Stream (Kinesis/DDB) |
|---|---|---|
| Delivery | Each message to ONE consumer | Each record to MULTIPLE consumers |
| After processing | Message deleted from queue | Record stays in stream (retained) |
| Ordering | Best-effort (Standard) or strict (FIFO) | Strict within shard (partition key) |
| Throughput | Nearly unlimited (Standard) | Depends on shard count |
| Scaling | Lambda auto-scales based on queue depth | Concurrency = number of shards x parallelization factor |
| Best for | Individual task processing, work queues, decoupling | Real-time analytics, multiple consumers, ordered processing |
# Create dead-letter queue
aws sqs create-queue --queue-name demo-orders-dlq
# Get DLQ ARN
DLQ_ARN=$(aws sqs get-queue-attributes --queue-url https://sqs.us-west-2.amazonaws.com/ACCOUNT/demo-orders-dlq \
--attribute-names QueueArn --query 'Attributes.QueueArn' --output text)
# Create main queue with redrive policy
aws sqs create-queue --queue-name demo-orders \
--attributes '{
"VisibilityTimeout": "180",
"RedrivePolicy": "{\"deadLetterTargetArn\":\"'$DLQ_ARN'\",\"maxReceiveCount\":\"3\"}"
}'
# handler.py
import json
def handler(event, context):
failed_ids = []
for record in event["Records"]:
body = json.loads(record["body"])
order_id = body.get("orderId", "unknown")
print(f"Processing order: {order_id}")
# Simulate failure for certain orders
if body.get("fail"):
failed_ids.append(record["messageId"])
continue
print(f" Success: {order_id}")
# Report partial batch failures
return {
"batchItemFailures": [
{"itemIdentifier": mid} for mid in failed_ids
]
}
aws lambda create-event-source-mapping \ --function-name demo-order-processor \ --event-source-arn arn:aws:sqs:us-west-2:ACCOUNT:demo-orders \ --batch-size 5 \ --function-response-types ReportBatchItemFailures
# Success message
aws sqs send-message --queue-url https://sqs.us-west-2.amazonaws.com/ACCOUNT/demo-orders \
--message-body '{"orderId":"ORD-001","amount":99.99}'
# Failure message (will retry then go to DLQ)
aws sqs send-message --queue-url https://sqs.us-west-2.amazonaws.com/ACCOUNT/demo-orders \
--message-body '{"orderId":"ORD-002","amount":50,"fail":true}'
aws sqs receive-message --queue-url https://sqs.us-west-2.amazonaws.com/ACCOUNT/demo-orders-dlq
ReportBatchItemFailures for SQS partial batchBisectBatchOnFunctionError for streamsIteratorAge (streams) and ApproximateAgeOfOldestMessage (SQS)Developing Serverless Solutions on AWS - Module 6 | Live Session Guide
Last updated: June 2026